#include "LoopManager.h"

#include "DateTimeUtility.h"
#include "CommandExecutor.h"
#include "CurrentVoltageManager.h"
#include "CommandDispatcher.h"
#include "CommandParser.h"


//static int i= 44;

LoopManager::LoopManager() : mtaskScheduler(TaskSchedulerSingleton::instance()), mconfigManager(ConfigManagerSingleton::instance())
    , mswitchDetectors(ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::AC_SWITCH_DETECTOR))
    , macDetectors(ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::ELECT))
    ,mcurrentVoltageManager(CurrentVoltageManagerSingleton::instance()) {
    initialize(ExtendDeviceEnum::CIRCUIT);

    mloopControllerConfig = mconfigManager.getExtendDeviceConfig().loopControllerInfo;

//    CommandDispatcherSingleton::instance().mnetworkListeners.push_back(this);
}



void LoopManager::returnToAutoMode() {
    mrunningCommandType = LoopCommandType::ONLINE_COMMAND;
    manualModalStopTime = 0;

    ExtendDevicePtr extendDevicePtr;
    LoopController* pLoopController;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }

        pLoopController = static_cast<LoopController*> (&*extendDevicePtr);
        pLoopController->returnToAutoMode();
    }

    onLoopChanged(getLoopStatus());
}



bool LoopManager::changeManualLoopStatus(const size_t index, const LoopStatus status) {
    size_t indexTemp = index;
    size_t singleLoopCount;
    bool changed = false;
    LoopController* pLoopController;
    ExtendDevicePtr extendDevicePtr;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }
        pLoopController = static_cast<LoopController*> (&*extendDevicePtr);
        singleLoopCount = pLoopController->mportCount;
        if (indexTemp >= singleLoopCount) {
            indexTemp -= singleLoopCount;
            continue;
        } else {
            onLoopChanged(index, pLoopController->changeManualLoopStatus(indexTemp, status));

            changed = true;
            manualModalStopTime = std::time(nullptr) + mmanualModeKeepTime;

            mrunningCommandType = LoopCommandType::MANUAL_COMMAND;

            mtaskScheduler.makeOnlyOneTask(mwptrTaskRecord, new TaskRecord(TaskletInfo{std::bind(&LoopManager::returnToAutoMode, this), nullptr}, DateTimeUtility::ClockTime_t(manualModalStopTime * DateTimeUtility::ClockTime_t::period::den)));

            break;
        }
    }

    if (!changed) {
        BUILD_EXCEPTION_PRINTF(FirmwareError::LOOP_COUNT_NO_MATCH, "Illegal index:%zu, all loop number is %zu", index, mportCount)
    }

    return changed;
}



void LoopManager::changeAutoLoopStatus(const LoopControlInfoPtr& command, const std::time_t delaySeconds) {
    LOG_WARN("mrunningCommandType:%c,command->commandType:%c", mrunningCommandType, command->commandType);
    if (LoopCommandType::MANUAL_COMMAND == mrunningCommandType || (LoopCommandType::ONLINE_DELAYED_COMMAND == mrunningCommandType && LoopCommandType::ONLINE_COMMAND > command->commandType)) {
        return;
    }

    LoopSize_t beginIndex = 0;
    LoopSize_t singleLoopCount;
    LoopStatus* pCommandData = command->loopStatus;
    LoopControlInfoPtr singleDeviceCommand;
    LoopController* pLoopController;
    ExtendDevicePtr extendDevicePtr;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }
        pLoopController = static_cast<LoopController*> (&*extendDevicePtr);
        singleLoopCount = pLoopController->mportCount;
        if (command->length <= beginIndex) {
            break;
        }

        LoopSize_t length = std::min(singleLoopCount, command->length - beginIndex);
        if (LoopCommandType::ONLINE_DELAYED_COMMAND == command->commandType) {
            pLoopController->changeManualLoopStatus(pCommandData + beginIndex, length);
        } else {
            pLoopController->changeAutoLoopStatus(pCommandData + beginIndex, length);
        }

        beginIndex += length;
    }

    mportCount = beginIndex;

    onLoopChanged(command);

    mrunningCommandType = command->commandType;
    if (0 < delaySeconds) {
        manualModalStopTime = std::time(nullptr) + delaySeconds + AUO_COMMAND_DELAY_APPEND;//delay plus 4 for server recovery
        mtaskScheduler.makeOnlyOneTask(mwptrTaskRecord, new TaskRecord(TaskletInfo{std::bind(&LoopManager::returnToAutoMode, this), nullptr}, DateTimeUtility::ClockTime_t(manualModalStopTime * DateTimeUtility::ClockTime_t::period::den)));
    } else {
        manualModalStopTime = 0;
        mtaskScheduler.cancelTask(mwptrTaskRecord);
    }
}


/*
void LoopManager::changeAutoLoopStatus(const LoopControlInfoPtr& command) {
    LoopSize_t beginIndex = 0;
    LoopSize_t singleLoopCount;
    LoopStatus* pCommandData = command->loopStatus;
    LoopControlInfoPtr singleDeviceCommand;
    LoopController* pLoopController;
    ExtendDevicePtr extendDevicePtr;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }
        pLoopController = static_cast<LoopController*> (&*extendDevicePtr);
        singleLoopCount = pLoopController->mportCount;
        if (command->length <= beginIndex) {
            break;
        }

        LoopSize_t length = std::min(singleLoopCount, command->length - beginIndex);

        pLoopController->changeAutoLoopStatus(pCommandData + beginIndex, length);

        beginIndex += length;
    }

    mportCount = beginIndex;

    onLoopChanged(command);
    if (command->length != beginIndex) {
        // LOG_WARN("command length:%s not equals LoopManager loop number:%s", command.second, beginIndex);
    }
}
*/


bool  LoopManager::validateCorrelationStatus() {
    bool result = false;

    std::string loopStatusString;
    getLoopStatus(loopStatusString);

    CommandParser& commandParser = CommandParserSingleton::instance();
    if (!mswitchDetectors.empty()) {
        ExtendDevicePtr extendDevicePtr = mswitchDetectors.front().lock();
        if (nullptr != extendDevicePtr) {
            extendDevicePtr->updateInformation();
            AcSwitchDetector* pacSwitchDetector = static_cast <AcSwitchDetector*>(extendDevicePtr->getDevice(ExtendDeviceEnum::AC_SWITCH_DETECTOR));

            result = pacSwitchDetector->analysisSwitchStatus(loopStatusString);
            if (result) {
                commandParser.sendAcSwitchStatus(pacSwitchDetector->mswitchMode, pacSwitchDetector->mloopSwitchStatus);
            }
        }
    }

    const std::string::size_type length = loopStatusString.size();
    std::string::size_type i;
    for (i = 0; i < length; ++i) {
        if (loopStatusString[i] & 1) {
            break;
        }
    }

    ExtendDevicePtr extendDevicePtr;
    AcDetector* pacDetector = nullptr;
    if (length > i) {
        if (!macDetectors.empty()) {
            extendDevicePtr = macDetectors.front().lock();
            if (nullptr != extendDevicePtr) {
                pacDetector = static_cast <AcDetector*>(&*extendDevicePtr);
                pacDetector->updateInformation();
                mcurrentVoltageManager.mforbidUpdate = true;
                result = pacDetector->analysisTrippingOperation(loopStatusString);
                mcurrentVoltageManager.mforbidUpdate = false;

//                if (result) {
//                   commandParser.sendCurrentAndVoltage();
//                }

                if (result) {
                    if (!mcircuitAlertSent) {
                        commandParser.sendCurrentAndVoltage();
                    }
                    ++mcircuitAlertSent;
                } else {
                    mcircuitAlertSent = 0;
                }
            }
        }
    }

    IExtendDeviceManager& extendDeviceManager = ExtendDeviceManagerSingleton::instance();

    ExtendDevicePtr innerAcDetectorPtr = extendDeviceManager.channelDevicesArray[0].second.front();
    pacDetector = static_cast <AcDetector*>(&*innerAcDetectorPtr);
    if (innerAcDetectorPtr != extendDevicePtr) {
        pacDetector->updateInformation();
    }

    mcurrentVoltageManager.mforbidUpdate = true;
    result = pacDetector->analysisVoltageAlert();
    mcurrentVoltageManager.mforbidUpdate = false;

    if (result) {
        if (!mpowerAlertSent) {
            commandParser.sendAlertInfo("ACPowerLost", StringUtility::EMPTY_STRING);
        }
        ++mpowerAlertSent;
    } else {
        mpowerAlertSent = 0;
    }



    return result;
}




bool  LoopManager::updateLoopControllerConfig(const LoopControllerConfigInfo& loopControllerConfig) {
    mloopControllerConfig = loopControllerConfig;

    LoopController* pLoopController;
    ExtendDevicePtr extendDevicePtr;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }
        pLoopController = static_cast<LoopController*> (&*extendDevicePtr);

        pLoopController->updateLoopControllerConfig(mloopControllerConfig);
    }

    return true;
}



void LoopManager::offlineCircleCommand() {
    TaskRecordPtr pTaskRecord = mwptrTaskRecord.lock();
    if (!pTaskRecord) {
        returnToAutoMode();
    }
}



void LoopManager::offline(INetwork* const network) {
    DateTimeUtility::ClockTime_t delay{(std::time(nullptr) + OFFLINE_RECOVER_DELAY) * DateTimeUtility::ClockTime_t::period::den};
    TaskRecord* ptaskRecord = new TaskRecord(TaskletInfo{std::bind(&LoopManager::offlineCircleCommand, this), nullptr}, delay, tick_count_t{OFFLINE_RECOVER_DELAY * DateTimeUtility::ClockTime_t::period::den},ETT_CIRCLE);
    mtaskScheduler.makeOnlyOneTask(mwptrOfflineTaskRecord, ptaskRecord);

}



void LoopManager::online(INetwork* const network) {

    mtaskScheduler.cancelTask(mwptrOfflineTaskRecord);
}



